#include "teststdafx.h"
#include "stdafx.h"
#include <gtest/gtest.h>

#include "Business/Policy/TrendBusiness.h"
#include "Utils/TimeoutNotifier.h"
#include "Utils/FastBlockQueue.h"
#include "Business/QueueContext.h"
#include "Repository/CancellationRepository.h"
#include "Repository/DealingRepository.h"
#include "Service/MarketStorage.h"
#include "Business/Customer.h"
#include "Business/Command.h"
#include "Business/ExchangeNotify.h"
#include "Business/RequestTimeout.h"

using namespace std;

typedef TrendBusiness::Argument BusinessArgument;
typedef TrendBusiness::Snapshot BusinessSnapshot;

class TrendBusinessTest : public testing::Test
{
protected:

	virtual void SetUp()
	{
		HANDLE hQuit = ::CreateEvent(NULL,TRUE,FALSE,NULL);
		m_customer.reset(new Customer("","",""));
		m_customer->SetOrginalAmount(10000.00);
		m_requestQueue.reset(FastBlockQueue::Create(hQuit));
		m_businessQueue.reset(FastBlockQueue::Create(hQuit));
		m_uiQueue.reset(FastBlockQueue::Create(hQuit));
		m_highTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_waitTimerQueue.reset(FastBlockQueue::Create(hQuit));
		m_dealingRepository.reset(new DealingRepository());
		m_cancellationRepository.reset(new CancellationRepository());
		m_queueContext.reset(new QueueContext(*m_requestQueue,*m_businessQueue,*m_uiQueue,*m_highTimerQueue,*m_waitTimerQueue));
		m_timeoutNotifier.reset(new TimeoutNotifier());

		InitMarket();

		m_business.reset(
			new TrendBusiness(*m_customer,
			BusinessArgument(0,10,1,30,30),
			m_marketStorage,
			*m_queueContext,
			*m_dealingRepository,
			*m_cancellationRepository
			)
			);
	}
	virtual void TearDown()
	{
	}
	void InitMarket()
	{
		m_marketStorage.Save(CreateBullMarket(0));
	}

	Market CreateBullMarket(double percent,CTime const& time = CTime::GetCurrentTime())
	{
		const double PRICE = 18680.00;
		const double OPEN_INT = 1000;
		Variety variety("zn1011",10,10);
		double lastPrice = PRICE * (1 + percent);
		double lastOpenInt = OPEN_INT *(1 + percent);
		Prices buyPrices;
		buyPrices[0] = Price(18690,2);
		Prices sellPrices;
		sellPrices[0] = Price(18680,2);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 20000;
		return Market(1,variety,lastPrice,lastOpenInt,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice,time); 
	}

	Market CreateMarket(double lastPrice, double lastOpenInt,CTime const& time = CTime::GetCurrentTime())
	{
		Variety variety("zn1011",10,10);
		Prices buyPrices;
		buyPrices[0] = Price(lastPrice,2);
		Prices sellPrices;
		sellPrices[0] = Price(lastPrice,2);
		double upperLimit = 40000;
		double lowerLimit = 20000;
		double preSettlementPrice  = 20000;
		return Market(1,variety,lastPrice,lastOpenInt,buyPrices,sellPrices,upperLimit,lowerLimit,preSettlementPrice,time); 
	}


	Market CreateBearMarket(double percent,CTime const& time = CTime::GetCurrentTime())
	{
		return CreateBullMarket(-percent,time);
	}

	void OnCommand(Command::TYPE type)
	{
		Command cmd = {0};
		cmd.type = type;
		cmd.business = m_business.get();
		m_business->OnCommand(cmd);
	}

	Dealing* OnOrdered()
	{
		bool quitFlag = false;
		QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);
		Dealing* dealing = m_dealingRepository->Get(((Dealing*)item.data)->GetLocalId());
		dealing->OnOrdered(FT("%d",dealing->GetLocalId()));
		m_business->OnDealing(*dealing);
		return dealing;
	}

	void OnTrade(Dealing* dealing,int quantity)
	{
		Trade trade(*dealing,dealing->GetOrderPrice(),quantity,dealing->GetSystemNo());
		dealing->OnTrade(trade);
		m_business->OnTrade(trade);
		m_business->OnDealing(*dealing);
	}

	void BullMarket(double percent, CTime const& time= CTime::GetCurrentTime())
	{
		m_business->OnMarket(CreateBullMarket(percent,time));
	}

	void BearMarket(double percent, CTime const& time= CTime::GetCurrentTime())
	{
		m_business->OnMarket(CreateBullMarket(-percent,time));
	}

#define ExpectSnapshot(status,openedPosition) \
	{\
		EXPECT_EQ(1,m_queueContext->GetUIQueue().Size());\
		bool quitFlag = false;\
		QueueItem const& item = m_queueContext->GetUIQueue().Pop(quitFlag);\
		EXPECT_EQ(QueueItem::COMMAND,item.type);\
		Command const& cmd = *(Command*)item.data;\
		EXPECT_EQ(Command::UI_UPDATE_BUSINESS_INFO,cmd.type);\
		BusinessSnapshot const& snapshot = *(BusinessSnapshot*)cmd.data;\
		EXPECT_STREQ(status,snapshot.GetStatus()); \
		EXPECT_EQ(openedPosition,snapshot.GetQuantity()); \
	}
#define ExpectCancel(localID) \
	{\
	EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());\
	bool quitFlag = false;\
	QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);\
	EXPECT_EQ(QueueItem::CANCELLATION,item.type);\
	Cancellation const& cancellation = *(Cancellation*)item.data;\
	EXPECT_EQ(localID,cancellation.GetOrderLocalId()); \
	}

#define ExpectOrder() \
	{\
	EXPECT_EQ(1,m_queueContext->GetRequestQueue().Size());\
	bool quitFlag = false;\
	QueueItem const& item = m_queueContext->GetRequestQueue().Pop(quitFlag);\
	EXPECT_EQ(QueueItem::ORDER,item.type);\
	}


	MarketStorage m_marketStorage;
	auto_ptr<FastBlockQueue> m_requestQueue;
	auto_ptr<FastBlockQueue> m_businessQueue;
	auto_ptr<FastBlockQueue> m_uiQueue;
	auto_ptr<FastBlockQueue> m_highTimerQueue;
	auto_ptr<FastBlockQueue> m_waitTimerQueue;
	auto_ptr<Customer> m_customer;
	auto_ptr<TrendBusiness> m_business;
	auto_ptr<DealingRepository> m_dealingRepository;
	auto_ptr<CancellationRepository> m_cancellationRepository;
	auto_ptr<QueueContext> m_queueContext;
	auto_ptr<TimeoutNotifier> m_timeoutNotifier;

	void foo();
	void foo1();
	void foo2();
};

//TEST_F(TrendBusinessTest,BullTest)/*
void TrendBusinessTest::foo() /* */
{
	int quantity = 10;
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	m_business->OnExchangeStatus(ExchangeStatus::CONTINOUS);
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	ExpectSnapshot("start",0);

	BullMarket(0);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	
	BullMarket(0.1);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BullMarket(0.05);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	CTime currentTime = CTime::GetCurrentTime();
	int minute = 1;
	BullMarket(0.10,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(1, m_business->GetKLine().GetSize());
	Market market = CreateBullMarket(0.1);
	EXPECT_DOUBLE_EQ(market.GetLastPrice(), m_business->GetKLine().Ref(0).GetMaxPrice());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BullMarket(0.11,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(2, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	EXPECT_TRUE(m_business->RefTmp3(0) > 0);

	BullMarket(0.13,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(3, m_business->GetKLine().GetSize());
	EXPECT_TRUE(m_business->RefTmp3(0) > 0);
	EXPECT_TRUE(m_business->RefTmp4(0) > 0);
	ExpectSnapshot("open sent",0);
	Dealing* dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("open cancel sent",0);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",2);

	BullMarket(0.16,currentTime + CTimeSpan(0,0,minute++,2));
	ExpectSnapshot("open sent",2);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("open cancel sent",2);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",4);


	BullMarket(0.18,currentTime);
	ExpectSnapshot("offset gain sent",4);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("offset gain cancel sent",4);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",2);


	BullMarket(0.14,currentTime + CTimeSpan(0,0,minute++,2));
	ExpectSnapshot("offset all sent",2);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	OnTrade(dealing,2);
	ExpectSnapshot("start",0);
}

//TEST_F(TrendBusinessTest,BearTest)/*
void TrendBusinessTest::foo2() /* */
{
	int quantity = 10;
	EXPECT_STREQ("editable",m_business->GetSnapshot().GetStatus());
	m_business->OnExchangeStatus(ExchangeStatus::CONTINOUS);
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	ExpectSnapshot("start",0);

	BearMarket(0);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BearMarket(0.1);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BearMarket(0.05);
	EXPECT_EQ(0, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	CTime currentTime = CTime::GetCurrentTime();
	int minute = 1;
	BearMarket(0.06,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(1, m_business->GetKLine().GetSize());
	Market market = CreateBearMarket(0.1);
	EXPECT_DOUBLE_EQ(market.GetLastPrice(), m_business->GetKLine().Ref(0).GetMinPrice());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BearMarket(0.07,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(2, m_business->GetKLine().GetSize());
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());

	BearMarket(0.09,currentTime + CTimeSpan(0,0,minute++,2));
	EXPECT_EQ(3, m_business->GetKLine().GetSize());
	ExpectSnapshot("open sent",0);
	Dealing* dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("open cancel sent",0);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",2);

	BearMarket(0.12,currentTime + CTimeSpan(0,0,minute++,2));
	ExpectSnapshot("open sent",2);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("open cancel sent",2);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",4);


	BearMarket(0.13,currentTime + CTimeSpan(0,0,minute++,2));
	ExpectSnapshot("offset gain sent",4);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	ExpectCancel(dealing->GetLocalId());
	ExpectSnapshot("offset gain cancel sent",4);
	OnTrade(dealing,2);
	ExpectSnapshot("opened",2);


	BearMarket(0.10,currentTime + CTimeSpan(0,0,minute++,2));
	ExpectSnapshot("offset all sent",2);
	dealing = OnOrdered();
	EXPECT_EQ(2,dealing->GetOrderQuantity());
	OnTrade(dealing,2);
	ExpectSnapshot("start",0);
}

//TEST_F(TrendBusinessTest,FormulaTest)/*
void TrendBusinessTest::foo1() /* */
{
	CTime currentTime = CTime::GetCurrentTime();
	int minute = 1;
	Market market0 = CreateMarket(31755,25.3);
	Market market1 = CreateMarket(31755,25.3,currentTime+ CTimeSpan(0,0,minute++,2));
	Market market2 = CreateMarket(31680,25.6,currentTime + CTimeSpan(0,0,minute++,2));
	Market market3 = CreateMarket(31645,25.8,currentTime + CTimeSpan(0,0,minute++,2));
	m_business->OnExchangeStatus(ExchangeStatus::CONTINOUS);
	OnCommand(Command::START_COMMAND);
	EXPECT_STREQ("start",m_business->GetSnapshot().GetStatus());
	ExpectSnapshot("start",0);

	m_business->OnMarket(market0);
	m_business->OnMarket(market1);
	m_business->OnMarket(market2);
	m_business->OnMarket(market3);

	EXPECT_NEAR(40.61,m_business->RefTmp4(0),0.01);
	EXPECT_NEAR(-35.272,m_business->RefTmp3(0),0.01);
}